/*
 * ITrackingPacket.java
 *
 * Created on April 15, 2008, 9:13 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package org.sunspotworld.mydatawrappers;

import java.io.IOException;
import org.sunspotworld.datawrappers.DataWrapper;

/**
 * The superclass for CowTracking data packets.
 * @author Douglas McClusky
 */
public abstract class TrackingPacket extends DataWrapper {
    public static final byte GPS_PACKET = 0;
    public static final byte NEIGHBOR_PACKET = 1;
    public static final byte TEMP_PACKET = 2;
    public static final byte LIGHT_PACKET = 3;
    public static final byte POWER_PACKET = 4;
    
    protected byte type;
    protected long senderAddress;
    protected long timestamp;
    protected static final int SIGN_SIZE = 1+2*8; //byte type + 2*long
    
    /**
     * the type indicates which subclass of TrackingPacket this is an instance of
     * @return
     */
    public byte getType() {
        return type;
    }
    
    /**
     * Transcribes the TrackingPacket to a Radio Packet Buffer
     * @param rg
     */
    public void writeToBuffer(byte[] buffer, int index) {
        byte[] packet = toByteArray();
        for (int i = 0; i < getSize(); i++) {
            buffer[index + i] = packet[i];
        }
        /*
        try {
            System.out.println("super\t" + TrackingPacketFactory.getInstance().constructDataWrapper(buffer, index).printEntryLine());
        } catch (IOException ex) {
            ex.printStackTrace();
        } //*/
    }
    
    /**
     * writes a header to a Radiogram for writeToRadiogram.  Signs the type of this packet and the address of the SPOT that generated it
     * @param rg
     * @throws java.io.IOException
     *
    protected void sign(Radiogram rg) throws IOException {
        //System.out.println(type);
        rg.writeByte(type);
        rg.writeLong(senderAddress);
    } 
    
    protected void readSign(Radiogram rg) throws IOException {
        //type = rg.readByte();
        senderAddress = rg.readLong();
    } //*/
    
    protected void readSign(byte[] b, int index) {
        type = b[index];
        senderAddress = byteArrayToLong(b, index + 1);
        timestamp = byteArrayToLong(b, index+9);
    }
    
    protected void sign(byte[] b) {
        b[0] = type;
        int i;
        int temp = 1;
        byte[] tempArray = longToByteArray(senderAddress);
        for (i=0; i<tempArray.length; i++) {
            b[i+1] = tempArray[i];
            temp++;
        }
        tempArray = longToByteArray(timestamp);
        for (i=0; i<tempArray.length; i++) {
            b[temp] = tempArray[i];
            temp++;
        }
    }
    
    protected double byteArrayToDouble(byte[] b, int startIndex) {
        return Double.longBitsToDouble(byteArrayToLong(b, startIndex));
    }
    
    protected static long byteArrayToLong(byte[] b, int startIndex) {
        return ((long)b[startIndex + 0] << 56)
                + (((long)b[startIndex + 1] & 0xFF) << 48)
                + (((long)b[startIndex + 2] & 0xFF) << 40)
                + (((long)b[startIndex + 3] & 0xFF) << 32)
                + (((long)b[startIndex + 4] & 0xFF) << 24)
                + (((long)b[startIndex + 5] & 0xFF) << 16)
                + (((long)b[startIndex + 6] & 0xFF) << 8)
                + ((long)b[startIndex + 7] & 0xFF);
    }
    
    protected int byteArrayToInt(byte [] b, int startIndex) {
        return (b[startIndex + 0] << 24)
                + ((b[startIndex + 1] & 0xFF) << 16)
                + ((b[startIndex + 2] & 0xFF) << 8)
                + (b[startIndex + 3] & 0xFF);
    }
    
    protected byte[] intToByteArray(int value) {
        return new byte[] {
                (byte)(value >>> 24),
                (byte)(value >>> 16),
                (byte)(value >>> 8),
                (byte)value};
    }
    
    protected byte[] doubleToByteArray(double value) {
        return longToByteArray(Double.doubleToLongBits(value));
    }
    
    protected byte[] longToByteArray(long value) {
        return new byte[] {
                (byte)(value >>> 56),
                (byte)(value >>> 48),
                (byte)(value >>> 40),
                (byte)(value >>> 32),
                (byte)(value >>> 24),
                (byte)(value >>> 16),
                (byte)(value >>> 8),
                (byte)value};
    }
}
